'''
This module contains the Short Time Schedullers of the Operative System we are going to develop. 
Extending to the Expropiative and Non-Expropiative abstract classes, there can be found schedullers
with the following policies:
First Come, First Serve Policy: dispatchs the first process to arrive the Ready Queue.
By Priorities: dispatchs with priority according to the processes' priorities.
Shortest Job First: dispatchs the process with the least processing time (note: this one is 
theorical only, not implementable in the real life -see the documentation for details-).
Round-Robin: yeeee-haw! This one is going to give a time-unit (known as "quantum") to every
process, this unit is going to be the processing time according to the unit.
'''
from main.processHandling import sortAndTakeTheShortest , sortAndReturnTheShortest ,  getProcessLength

#-----------------------------------------------------------------------#
#------------------CLASS AbstractScheduler------------------------------#
#-----------------------------------------------------------------------#

class AbstractScheduler():
#--------------------------INSTANCIATION--------------------------------#            
    def __init__(self,processesQueue,aCPU,aIOQueue):
        self.processes = processesQueue # TIENE QUE SER UNA QUEUE, SON THREAD-SAFE
        self.cpu = aCPU
        self.io = aIOQueue 
        if type(self) is AbstractScheduler: #This is an Abstract class
            raise Exception('You can t create an instance of an Abstract Class!')
        else:
            pass 
            
    def moveProcessToCPU(self,aProcess):
        if(self.cpu.isNotWorking()):
            self.cpu.currentProcess = aProcess
        else:
            self.processes.insert(0,aProcess)

    def dispatchAProcess(self):
        if(self.processes.length()>0):
            self.manageAProcess()
                
    def manageAProcess(self):
        pass

#-----------------------------------------------------------------------#
#------------------CLASS AbstractScheduler_NonExpropiative-----------------#
#-----------------------------------------------------------------------#

class AbstractScheduler_NonExpropiative(AbstractScheduler):        
    def __init__(self,processes,aCPU,aIOQueue):
        AbstractScheduler.__init__(self,processes,aCPU,aIOQueue)
        if type(self) is AbstractScheduler_NonExpropiative: #This is an Abstract class
            raise Exception('You can t create an instance of an Abstract Class!')
        else:
            pass  

#-----------------------------------------------------------------------#
#------------------CLASS Scheduler_FirstComeFirstServe------------------#
#-----------------------------------------------------------------------#
class Scheduler_FirstComeFirstServe(AbstractScheduler_NonExpropiative):
    def __init__(self,processes,aCPU,aIOQueue):
        AbstractScheduler_NonExpropiative.__init__(self,processes,aCPU,aIOQueue)

    def manageAProcess(self):
        aProcess = self.processes.pop(0)
        self.moveProcessToCPU(aProcess) #CAUTION! Partial


#-----------------------------------------------------------------------#
#------------------CLASS Scheduler_ShortestJobFirst_NE------------------#
#-----------------------------------------------------------------------#
class Scheduler_ShortestJobFirst_NE(AbstractScheduler_NonExpropiative):
    
    def manageAProcess(self):
        shortest = sortAndTakeTheShortest(self)
        self.moveProcessToCPU(shortest)


    
#-----------------------------------------------------------------------#
#------------------CLASS Scheduler_ByPriorities-------------------------#
#-----------------------------------------------------------------------#


class Scheduler_ByPriorities(AbstractScheduler_NonExpropiative):

   
#--------------------------PARTIAL METHODS----------------------------------#            

    def getBiggestPriority(self):
        maxP = self.processes.pop(0)
        for p in self.processes.processes:
            if(p.pcb.priority < maxP.pcb.priority):
                maxP = p
        return maxP
             

    def manageAProcess(self):
        processWithBP = self.getBiggestPriority()
        self.moveProcessToCPU(processWithBP)
        
#-----------------------------------------------------------------------#
#------------------CLASS AbstractScheduler_Expropiative-----------------#
#-----------------------------------------------------------------------#
class AbstractScheduler_Expropiative(AbstractScheduler):        
    def __init__(self,processes,aCPU,aIOQueue):
        AbstractScheduler.__init__(self,processes,aCPU,aIOQueue)
        if type(self) is AbstractScheduler_Expropiative: #This is an Abstract class
            raise Exception('You can t create an instance of an Abstract Class!')
        else:
            pass    
       
        
    def needToExpropiate(self):
        pass
        
#-----------------------------------------------------------------------#
#------------------CLASS Scheduler_ShortestJobFirst_E-------------------#
#-----------------------------------------------------------------------#
class Scheduler_ShortestJobFirst_E(AbstractScheduler_Expropiative):
    
    def manageAProcess(self):
        shortest = sortAndTakeTheShortest(self)
        self.moveProcessToCPU(shortest)

    def inspect(self):
        if( self.needToExpropiate() == 1):
            self.cpu.expropiate()
   
    def needToExpropiate(self):
        yesItDoes = False
        # ME PARECE QUE CON EL NUEVO MODELO ACA TENEMOS CHECKEOS QUE SE ESTAN HACIENDO DE MAS (NO AFECTAN NEGATIVAMENTE)
        if((not self.cpu.currentProcess == None)  &  self.processes.length() > 0):
            if( getProcessLength(sortAndReturnTheShortest(self)) <  getProcessLength(self.cpu.currentProcess)):
                yesItDoes = True
        return yesItDoes
               
 
#-----------------------------------------------------------------------#
#------------------CLASS Scheduler_RoundRobin_E-------------------------#
#-----------------------------------------------------------------------#
class Scheduler_RoundRobin_E(AbstractScheduler_Expropiative):
    def __init__(self,processes,aCPU,aIOQueue):
        AbstractScheduler_Expropiative.__init__(self, processes, aCPU, aIOQueue)

    def manageAProcess(self):
        aProcess = self.processes.pop(0)
        self.moveProcessToCPU(aProcess) 
    
               
